#include "socket_util.h"
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

void new_sockaddr(struct sockaddr_in* addr, const char *ip_addr, uint16_t port) {
    memset(addr, 0, sizeof(*addr));  //每个字节都用0填充
    addr->sin_family = AF_INET;  //使用IPv4地址
    addr->sin_addr.s_addr = inet_addr(ip_addr);  //具体的IP地址
    addr->sin_port = htons(port);  //端口
}

const int LEN = 64;

void send_str(int sock, const char *str) {
    send(sock, str, LEN, 0);
}

const char *recv_str(int sock) {
    char *str = malloc(LEN);
    recv(sock, (void *)str, LEN, 0);
    return str;
}

void print_endl() {
    printf("\n");
    fflush(stdout);
}

void print_game_msg(enum GAME_MSG action_type) {
    switch (action_type) {
        case GAME_MSG_START_ROUND:
            printf("GAME_MSG_START_ROUND");
            break;
        case GAME_MSG_CLOTH:
            printf("GAME_MSG_CLOTH");
            break;
        case GAME_MSG_SCISSORS:
            printf("GAME_MSG_SCISSORS");
            break;
        case GAME_MSG_STONE:
            printf("GAME_MSG_STONE");
            break;
        case GAME_MSG_FINAL_LOST:
            printf("GAME_MSG_FINAL_LOST");
            break;
        case GAME_MSG_FINAL_WIN:
            printf("GAME_MSG_FINAL_WIN");
            break;
        case GAME_MSG_FINAL_DRAW:
            printf("GAME_MSG_FINAL_DRAW");
            break;
    }
}

void send_game_msg(int sock, enum GAME_MSG action_type) {
    char *buffer = (char *)malloc(LEN);
    sprintf(buffer, "%d", action_type);
    send_str(sock, buffer);
    printf("[Game Message Sent]: to sock %d << ", sock);
    print_game_msg(action_type);
    print_endl();
    free(buffer);
}

enum GAME_MSG recv_game_msg(int sock) {
    const char *str = recv_str(sock);
    printf("[Recv Str]: %s", str);
    print_endl();
    enum GAME_MSG msg = (enum GAME_MSG)(str[0] - '0');
    free((void *)str);
    printf("[Game Message Recv]: fr sock %d >> ", sock);
    print_game_msg(msg);
    print_endl();
    return msg;
}

void new_room(struct room* room, int serv_sock, size_t rounds_len) {
    for (int i = 0; i < 2; i++) {
        struct sockaddr_in clnt_addr;
        socklen_t clnt_addr_size = sizeof(clnt_addr);
        room->player[i] = accept(serv_sock, 
            (struct sockaddr*)&clnt_addr, &clnt_addr_size);
        printf("[Connection Info]: Player %d Entered Room.", i);
        print_endl();
    }
    room->rounds_len = rounds_len;
    room->rounds = (struct round *)malloc(sizeof(struct round) * rounds_len);
    room->played_rounds = 0;
}

void destroy_room(struct room* room) {
    free(room->rounds);
    for (int i = 0; i < 2; i++) {
        close(room->player[i]);
    }
}

enum WINNER get_winner(enum GAME_MSG action0, enum GAME_MSG action1) {
    enum WINNER winner;
    if (action0 == GAME_MSG_CLOTH && action1 == GAME_MSG_STONE || 
            action0 == GAME_MSG_STONE && action1 == GAME_MSG_SCISSORS || 
            action0 == GAME_MSG_SCISSORS && action1 == GAME_MSG_CLOTH) {
        winner = PLAYER_0;
    } else if (action0 == action1) {
        winner = DRAW;
    } else {
        winner = PLAYER_1;
    }
    return winner;
}

// 返回1,如果玩成功了，如果这个房间已经玩够了，返回0
int play_new_round(struct room* room) {
    if (room->played_rounds == room->rounds_len) {
        int player0_wins = 0, player1_wins = 0;
        for (int i = 0; i < room->rounds_len; i++) {
            switch(room->rounds[i].winner) {
                case PLAYER_0:
                    player0_wins++;
                    break;
                case PLAYER_1:
                    player1_wins++;
                    break;
                case DRAW:
                    break;
            }
        }
        enum WINNER winner;
        if (player0_wins > player1_wins) {
            winner = PLAYER_0;
        } else if (player1_wins > player0_wins){
            winner = PLAYER_1;
        } else {
            winner = DRAW;
        }
        for (int i = 0; i < 2; i++) {
            enum GAME_MSG msg;
            switch (winner) {
                case PLAYER_0:
                    if (i == 0) msg = GAME_MSG_FINAL_WIN;
                    else msg = GAME_MSG_FINAL_LOST;
                    break;
                case PLAYER_1:
                    if (i == 1) msg = GAME_MSG_FINAL_WIN;
                    else msg = GAME_MSG_FINAL_LOST;
                    break;
                case DRAW:
                    msg = GAME_MSG_FINAL_DRAW;
                    break;
            }
            send_game_msg(room->player[i], msg);
        }
        printf("[Final Info]: Player 0 (socket %d) wins %d round(s)!", 
                room->player[0], player0_wins);
        print_endl();
        printf("[Final Info]: Player 1 (socket %d) wins %d round(s)!", 
                room->player[1], player1_wins);
        print_endl();
        printf("[Final Info]: draws %ld round(s)!", 
                room->rounds_len - player0_wins - player1_wins);
        print_endl();
        return 0;
    }
    struct round *round = &room->rounds[room->played_rounds++];
    for (int i = 0; i < 2; i++) {
        send_game_msg(room->player[i], GAME_MSG_START_ROUND);
    }
    printf("[Game Info]: round %ld starts!", room->played_rounds);
    print_endl();
    for (int i = 0; i < 2; i++) {
        round->action[i] = recv_game_msg(room->player[i]);
    }
    for (int i = 0; i < 2; i++) {
        send_game_msg(room->player[i], round->action[(i + 1) % 2]);
    }
    enum GAME_MSG action0 = round->action[0];
    enum GAME_MSG action1 = round->action[1];
    round->winner = get_winner(action0, action1);

    return 1;
}